From 20aff3a45268e5a1607e62ea83a8b3afefb47fab Mon Sep 17 00:00:00 2001 From: DCFApixels <99481254+DCFApixels@users.noreply.github.com> Date: Sat, 5 Apr 2025 18:08:07 +0800 Subject: [PATCH] update LayersMap stash --- src/EcsPipeline.Builder.cs | 40 +- src/Utils/DependencyGraph.cs | 816 +++++++++++++++++++++++++++++++ src/Utils/EcsPipelineTemplate.cs | 3 +- src/Utils/LayersMap.cs | 647 ------------------------ 4 files changed, 840 insertions(+), 666 deletions(-) create mode 100644 src/Utils/DependencyGraph.cs delete mode 100644 src/Utils/LayersMap.cs diff --git a/src/EcsPipeline.Builder.cs b/src/EcsPipeline.Builder.cs index 2966088..0beb97d 100644 --- a/src/EcsPipeline.Builder.cs +++ b/src/EcsPipeline.Builder.cs @@ -63,7 +63,7 @@ namespace DCFApixels.DragonECS Injector.AddNode(); Injector.AddNode(); - Layers = new LayersMap(this, PRE_BEGIN_LAYER, BEGIN_LAYER, BASIC_LAYER, END_LAYER, POST_END_LAYER); + //Layers = new DependencyGraph(this, PRE_BEGIN_LAYER, BEGIN_LAYER, BASIC_LAYER, END_LAYER, POST_END_LAYER); } #endregion @@ -233,21 +233,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 LinkedListCountIterator(_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 @@ -565,8 +566,11 @@ namespace DCFApixels.DragonECS [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(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..05080da --- /dev/null +++ b/src/Utils/DependencyGraph.cs @@ -0,0 +1,816 @@ +using DCFApixels.DragonECS.Internal; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +namespace DCFApixels.DragonECS.Core +{ + using VertextID = DependencyGraphVertextID; + public enum DependencyGraphVertextID : short { NULL = 0 } + public interface IDependencyGraph + { + int Count { get; } + VertextID AddVertex(T vertex, bool isLocked); + bool ContainsVertex(T vertex); + VertextID GetVertexID(T vertex); + bool RemoveVertex(T vertex); + void AddBeforeDependency(VertextID vertexID, VertextID otherVertexID); + void AddAfterDependency(VertextID vertexID, VertextID otherVertexID); + T[] Sort(); + } + public class LayersMap + { + private readonly IDependencyGraph _graph; + private readonly EcsPipeline.Builder _pipelineBuilder; + + #region Properties + public EcsPipeline.Builder Back + { + get { return _pipelineBuilder; } + } + public int Count + { + get { return _graph.Count; } + } + #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) + { + VertextID 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) + { + VertextID 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 + + public struct MoveHandler + { + private readonly IDependencyGraph _graph; + private readonly EcsPipeline.Builder _pipelineBuilder; + private readonly VertextID _layerID; + private readonly IEnumerable _layersRange; + + #region Properties + public EcsPipeline.Builder Back + { + get { return _pipelineBuilder; } + } + #endregion + + #region Constructors + public MoveHandler(IDependencyGraph graph, EcsPipeline.Builder pipelineBuilder, VertextID id) + { + _graph = graph; + _pipelineBuilder = pipelineBuilder; + _layerID = id; + _layersRange = null; + } + public MoveHandler(IDependencyGraph graph, EcsPipeline.Builder pipelineBuilder, IEnumerable layersRange) + { + _graph = graph; + _pipelineBuilder = pipelineBuilder; + _layerID = VertextID.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 != VertextID.NULL) + { + _graph.AddBeforeDependency(_layerID, _graph.GetVertexID(targetLayer)); + } + if (_layersRange != null) + { + foreach (var layer in _layersRange) + { + _graph.AddBeforeDependency(_graph.GetVertexID(layer), _graph.GetVertexID(targetLayer)); + } + } + 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 != VertextID.NULL) + { + _graph.AddAfterDependency(_graph.GetVertexID(targetLayer), _layerID); + } + if (_layersRange != null) + { + foreach (var layer in _layersRange) + { + _graph.AddBeforeDependency(_graph.GetVertexID(targetLayer), _graph.GetVertexID(layer)); + } + } + return this; + } + #endregion + } + + #region Other + public bool Contains(string layer) { return _graph.ContainsVertex(layer); } + + //public Enumerator GetEnumerator() { return new Enumerator(this); } + //IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } + //IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } + //public struct Enumerator : IEnumerator + //{ + // private DependencyGraph _map; + // private int _index; + // public Enumerator(DependencyGraph map) + // { + // _map = map; + // _index = -1; + // } + // public string Current + // { + // get { return _map._vertexInfos._items[_index].name; } + // } + // object IEnumerator.Current { get { return Current; } } + // public bool MoveNext() + // { + // if (_index++ >= _map._vertexInfos.Count) { return false; } + // ref var info = ref _map._vertexInfos._items[_index]; + // if (info.isContained == false) + // { + // return MoveNext(); + // } + // else + // { + // return true; + // } + // } + // public void Reset() { _index = -1; } + // public void Dispose() { } + //} + #endregion + + #region Build + public string[] Build() + { + return _graph.Sort(); + } + #endregion + + #region Obsolete + [Obsolete("Use " + nameof(DependencyGraph) + ".Add(layer).Before(targetLayer).Back;")] + public EcsPipeline.Builder Insert(string targetLayer, string newLayer) + { + Add(newLayer).Before(targetLayer); + return _pipelineBuilder; + } + [Obsolete("Use " + nameof(DependencyGraph) + ".Add(layer).After(targetLayer).Back;")] + public EcsPipeline.Builder InsertAfter(string targetLayer, string newLayer) + { + Add(newLayer).After(targetLayer); + return _pipelineBuilder; + } + [Obsolete("Use " + nameof(DependencyGraph) + ".Move(layer).Before(targetLayer).Back;")] + public EcsPipeline.Builder Move(string targetLayer, string newLayer) + { + Move(newLayer).Before(targetLayer); + return _pipelineBuilder; + } + [Obsolete("Use " + nameof(DependencyGraph) + ".Move(layer).After(targetLayer).Back;")] + public EcsPipeline.Builder MoveAfter(string targetLayer, string newLayer) + { + Move(newLayer).After(targetLayer); + return _pipelineBuilder; + } + [Obsolete("Use " + nameof(DependencyGraph) + ".Add(layers).Before(targetLayer).Back;")] + public EcsPipeline.Builder Insert(string targetLayer, params string[] newLayers) + { + Add(newLayers).Before(targetLayer); + return _pipelineBuilder; + } + [Obsolete("Use " + nameof(DependencyGraph) + ".Add(layers).After(targetLayer).Back;")] + public EcsPipeline.Builder InsertAfter(string targetLayer, params string[] newLayers) + { + Add(newLayers).After(targetLayer); + return _pipelineBuilder; + } + [Obsolete("Use " + nameof(DependencyGraph) + ".Move(layers).Before(targetLayer).Back;")] + public EcsPipeline.Builder Move(string targetLayer, params string[] movingLayers) + { + Move(movingLayers).Before(targetLayer); + return _pipelineBuilder; + } + [Obsolete("Use " + nameof(DependencyGraph) + ".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; + } + } + [Obsolete("Use MergeWith(LayersMap)")] + public void MergeWith(IReadOnlyList other) + { + foreach (var layer in other) + { + Add(layer); + } + } + #endregion + } + + + + public partial class DependencyGraph : IEnumerable, IDependencyGraph + { + #region IDependencyGraph + VertextID IDependencyGraph.AddVertex(string vertex, bool isLocked) + { + var result = GetVertexID(vertex); + Add_Internal(result); + if (isLocked) + { + LockVertex(vertex); + } + return result; + } + bool IDependencyGraph.ContainsVertex(string vertex) + { + return GetVertexInfo(GetVertexID(vertex)).isContained; + } + VertextID IDependencyGraph.GetVertexID(string vertex) + { + return GetVertexID(vertex); + } + bool IDependencyGraph.RemoveVertex(string vertex) + { + var result = GetVertexID(vertex); + return Remove_Internal(result); + } + void IDependencyGraph.AddAfterDependency(VertextID fromoVertexID, VertextID toVertexID) + { + AddDependency_Internal(fromoVertexID, toVertexID, false); + } + void IDependencyGraph.AddBeforeDependency(VertextID fromoVertexID, VertextID toVertexID) + { + AddDependency_Internal(fromoVertexID, toVertexID, true); + } + string[] IDependencyGraph.Sort() + { + return Build(); + } + #endregion + + private readonly Dictionary _vertexIDs = new Dictionary(32); + private StructList _vertexInfos = new StructList(32); + private VertextID GetVertexID(string vertext) + { + if (_vertexIDs.TryGetValue(vertext, out VertextID layerID) == false) + { + layerID = (VertextID)_vertexInfos.Count; + _vertexInfos.Add(default); + + _vertexIDs[vertext] = layerID; + ref var layerInfo = ref GetVertexInfo(layerID); + layerInfo.name = vertext; + } + return layerID; + } + private ref VertexInfo GetVertexInfo(VertextID vertexID) + { + return ref _vertexInfos._items[(int)vertexID]; + } + [DebuggerDisplay("{name}")] + private struct VertexInfo + { + public string name; + public int insertionIndex; + public bool isLocked; + public bool isContained; + public bool isBefore; + //build + public bool hasAnyDependency; + public int inDegree; + public int sortingIndex; + public int leftBeforeIndex; + public VertexInfo(string name) : this() + { + this.name = name; + } + } + + private List<(VertextID from, VertextID to)> _dependencies = new List<(VertextID, VertextID)>(16); + private readonly VertextID _basicVertexID; + private int _increment = 0; + private int _count; + + public IEnumerable<(string from, string to)> Deps + { + get + { + return _dependencies.Select(o => (GetVertexInfo(o.from).name, GetVertexInfo(o.to).name)); + } + } + + #region Properties + public int Count + { + get { return _count; } + } + #endregion + + #region Constructors + public DependencyGraph() + { + GetVertexID(""); + _basicVertexID = VertextID.NULL; + } + public DependencyGraph(string basicVertexName) + { + GetVertexID(""); + _basicVertexID = GetVertexID(basicVertexName); + LockVertex(basicVertexName); + } + #endregion + + #region Methods + private void LockVertex(string veretex) + { + GetVertexInfo(GetVertexID(veretex)).isLocked = true; + } + private void Add_Internal(VertextID id) + { + ref var info = ref GetVertexInfo(id); + if (info.isContained == false || info.isLocked == false) + { + _count++; + info.isContained = true; + info.insertionIndex = _increment++; + } + } + private bool Remove_Internal(VertextID id) + { + ref var info = ref GetVertexInfo(id); + bool result = false; + if (info.isLocked) { throw new Exception($"The {info.name} vertex cannot be removed"); } + if (info.isContained) + { + _count--; + info.isContained = false; + result = true; + } + info.insertionIndex = 0; + return result; + } + private void AddDependency_Internal(VertextID from, VertextID to, bool isBefore = false) + { + + ref var fromInfo = ref GetVertexInfo(from); + ref var toInfo = ref GetVertexInfo(to); + fromInfo.hasAnyDependency = true; + toInfo.hasAnyDependency = true; + + if (isBefore) + { + //GetLayerInfo(from).insertionIndex = 1000 - (_increment++); + fromInfo.isBefore = true; + //_dependencies.Insert(0, (from, to)); + } + else + { + //GetLayerInfo(from).insertionIndex = _increment++; + fromInfo.isBefore = false; + //_dependencies.Add((from, to)); + } + //_dependencies.Insert(0, (from, to)); + _dependencies.Add((from, to)); + } + private void AddDependency_Internal(string from, string to, bool isBefore = false) + { + AddDependency_Internal(GetVertexID(from), GetVertexID(to), isBefore); + } + #endregion + + #region MergeWith + public void MergeWith(DependencyGraph other) + { + foreach (var otherDependency in other._dependencies) + { + AddDependency_Internal(other.GetVertexInfo(otherDependency.from).name, other.GetVertexInfo(otherDependency.to).name); + } + for (int i = 0; i < other._vertexInfos.Count; i++) + { + VertextID otherLayerID = (VertextID)i; + ref var otherLayerInfo = ref other.GetVertexInfo(otherLayerID); + Add_Internal(GetVertexID(otherLayerInfo.name)); + } + } + #endregion + + #region Build + private unsafe void TopoSorting(UnsafeArray sortingBuffer) + { + VertextID[] nodes = new VertextID[_count]; + var adjacency = new List<(VertextID To, int DependencyIndex)>[_vertexInfos.Count]; + + for (int i = 0, j = 0; i < _vertexInfos.Count; i++) + { + VertextID layerID = (VertextID)i; + ref var info = ref GetVertexInfo(layerID); + adjacency[(int)layerID] = new List<(VertextID To, int DependencyIndex)>(); + _vertexInfos._items[(int)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 (_basicLayerID != LayerID.NULL) + //{ + // var basicLayerAdjacencyList = adjacency[(int)_basicLayerID]; + // int inserIndex = basicLayerAdjacencyList.Count; + // //for (int i = _layerInfos.Count - 1; i >= 0; i--) + // for (int i = 0; i < _layerInfos.Count; i++) + // { + // var id = (LayerID)i; + // ref var toInfo = ref _layerInfos._items[i]; + // if(toInfo.isContained && toInfo.hasAnyDependency == false) + // { + // //toInfo.insertionIndex = -toInfo.insertionIndex; + // basicLayerAdjacencyList.Insert(inserIndex, (id, 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)); + + //List result = new List(nodes.Length); + int resultCount = 0; + + while (zeroInDegree.Count > 0) + { + var current = zeroInDegree[0]; + zeroInDegree.RemoveAt(0); + + //result.Add(GetVertexInfo(current).name); + GetVertexInfo(current).sortingIndex = resultCount; + sortingBuffer.ptr[resultCount++] = current; + + var adjacencyList = adjacency[(int)current]; + //for (int i = adjacencyList.Count - 1; i >= 0; i--) + 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); + + //zeroInDegree.Add(neighbor); + //zeroInDegree = zeroInDegree.OrderBy(id => GetLayerInfo(id).insertionIndex).ToList(); + } + } + } + + 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 unsafe void ReoderInsertionIndexes(UnsafeArray sortingBuffer) + { + for (int i = 0; i < _vertexInfos.Count; i++) + { + ref var info = ref _vertexInfos._items[i]; + if (info.isContained == false) { continue; } + info.leftBeforeIndex = info.isBefore ? int.MaxValue : 0; + } + + foreach (var dependency in _dependencies) + { + ref var fromInfo = ref GetVertexInfo(dependency.from); + if (fromInfo.isBefore) + { + 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.isBefore) + { + 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 unsafe void MoveElement(ref UnsafeArray array, int oldIndex, int newIndex) where T : unmanaged + { + var ptr = array.ptr; + if (oldIndex == newIndex) return; + + // Сохраняем элемент для перемещения + T item = ptr[oldIndex]; + + int elementSize = sizeof(T); + 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; + } + + public unsafe string[] Build() + { + const int BUFFER_THRESHOLD = 256; + if(_count <= BUFFER_THRESHOLD) + { + var ptr = stackalloc VertextID[_count]; + var buffer = UnsafeArray.Manual(ptr, _count); + TopoSorting(buffer); + ReoderInsertionIndexes(buffer); + TopoSorting(buffer); + return buffer.Select(id => GetVertexInfo(id).name).ToArray(); + } + else + { + var ptr = TempBuffer.Get(_count); + var buffer = UnsafeArray.Manual(ptr, _count); + TopoSorting(buffer); + ReoderInsertionIndexes(buffer); + TopoSorting(buffer); + return buffer.Select(id => GetVertexInfo(id).name).ToArray(); + } + } + #endregion + + #region FindCycles + private List FindCycle( + List<(VertextID To, int DependencyIndex)>[] adjacency, + VertextID[] 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( + VertextID node, + List<(VertextID 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<(VertextID To, int DependencyIndex)>[] adjacency) + { + var cycleEdges = new HashSet<(VertextID, VertextID)>(); + 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).name}->{GetVertexInfo(dep.to).name}"); + } + } + } + return dependencies.Distinct().ToArray(); + } + #endregion + + #region Other + public bool Contains(string layer) { return GetVertexInfo(GetVertexID(layer)).isContained; } + + public Enumerator GetEnumerator() { return new Enumerator(this); } + IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } + IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } + public struct Enumerator : IEnumerator + { + private DependencyGraph _map; + private int _index; + public Enumerator(DependencyGraph map) + { + _map = map; + _index = -1; + } + public string Current + { + get { return _map._vertexInfos._items[_index].name; } + } + object IEnumerator.Current { get { return Current; } } + public bool MoveNext() + { + if (_index++ >= _map._vertexInfos.Count) { return false; } + ref var info = ref _map._vertexInfos._items[_index]; + if(info.isContained == false) + { + return MoveNext(); + } + else + { + return true; + } + } + public void Reset() { _index = -1; } + public void Dispose() { } + } + #endregion + } +} \ No newline at end of file diff --git a/src/Utils/EcsPipelineTemplate.cs b/src/Utils/EcsPipelineTemplate.cs index 59617df..3883ea7 100644 --- a/src/Utils/EcsPipelineTemplate.cs +++ b/src/Utils/EcsPipelineTemplate.cs @@ -21,7 +21,8 @@ namespace DCFApixels.DragonECS [DataMember] public Record[] records; void IEcsModule.Import(EcsPipeline.Builder b) { - b.Layers.MergeWith(layers); + throw new NotImplementedException(); + //b.Layers.MergeWith(layers); foreach (var s in records) { if (s.target == null) { continue; } diff --git a/src/Utils/LayersMap.cs b/src/Utils/LayersMap.cs deleted file mode 100644 index c4aa231..0000000 --- a/src/Utils/LayersMap.cs +++ /dev/null @@ -1,647 +0,0 @@ -using DCFApixels.DragonECS.Internal; -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; - -namespace DCFApixels.DragonECS.Core -{ - public partial class LayersMap : IEnumerable - { - private readonly Dictionary _layerIds = new Dictionary(32); - private StructList _layerInfos = new StructList(32); - private LayerID GetLayerID(string layer) - { - if (_layerIds.TryGetValue(layer, out LayerID layerID) == false) - { - layerID = (LayerID)_layerInfos.Count; - _layerInfos.Add(default); - - _layerIds[layer] = layerID; - ref var layerInfo = ref GetLayerInfo(layerID); - layerInfo.name = layer; - } - return layerID; - } - private ref LayerInfo GetLayerInfo(LayerID layerID) - { - return ref _layerInfos._items[(int)layerID]; - } - [DebuggerDisplay("{name}")] - private struct LayerInfo - { - public string name; - public int insertionIndex; - public bool isLocked; - public bool isContained; - public bool isBefore; - //build - public int inDegree; - public bool hasAnyDependency; - public LayerInfo(string name) : this() - { - this.name = name; - } - } - - private readonly EcsPipeline.Builder _source; - private List<(LayerID From, LayerID To)> _dependencies = new List<(LayerID, LayerID)>(16); - private readonly LayerID _rootLayerID; - private readonly LayerID _basicLayerID; - private int _increment = 0; - private int _count; - - public IEnumerable<(string from, string to)> Deps - { - get - { - return _dependencies.Select(o => (GetLayerInfo(o.From).name, GetLayerInfo(o.To).name)); - } - } - - #region Properties - public int Count - { - get { return _count; } - } - #endregion - - #region Constructors - public LayersMap(EcsPipeline.Builder source = null) - { - GetLayerID(""); - _source = source; - _rootLayerID = LayerID.NULL; - _basicLayerID = LayerID.NULL; - } - public LayersMap(EcsPipeline.Builder source, string basicLayerName) - { - GetLayerID(""); - _source = source; - - Add(basicLayerName); - - _rootLayerID = LayerID.NULL; - _basicLayerID = GetLayerID(basicLayerName); - LockLayer(basicLayerName); - } - public LayersMap(EcsPipeline.Builder source, string preBeginlayer, string beginlayer, string basicLayer, string endLayer, string postEndLayer) - { - GetLayerID(""); - _source = source; - - Add(preBeginlayer); - //.Before(beginlayer); - Add(beginlayer) - //.Before(basicLayer) - .After(preBeginlayer); - Add(basicLayer) - //.Before(endLayer) - .After(beginlayer); - Add(endLayer) - //.Before(postEndLayer) - .After(basicLayer); - Add(postEndLayer) - .After(endLayer); - - _rootLayerID = GetLayerID(preBeginlayer); - _basicLayerID = GetLayerID(basicLayer); - LockLayer(preBeginlayer); - LockLayer(beginlayer); - LockLayer(basicLayer); - LockLayer(endLayer); - LockLayer(postEndLayer); - } - #endregion - - #region Methods - private void LockLayer(string layer) - { - GetLayerInfo(GetLayerID(layer)).isLocked = true; - } - private void Add_Internal(LayerID id) - { - ref var info = ref GetLayerInfo(id); - if (info.isLocked) { return; } - if (info.isContained == false) - { - _count++; - info.isContained = true; - } - info.insertionIndex = _increment++; - } - private void Remove_Internal(LayerID id) - { - ref var info = ref GetLayerInfo(id); - if (info.isLocked) { throw new Exception($"The {info.name} layer cannot be removed"); } - if (info.isContained) - { - _count--; - info.isContained = false; - } - info.insertionIndex = 0; - } - private void AddDependency_Internal(LayerID from, LayerID to, bool isBefore = false) - { - GetLayerInfo(from).hasAnyDependency = true; - GetLayerInfo(to).hasAnyDependency = true; - - if (isBefore) - { - //GetLayerInfo(from).insertionIndex = 1000 - (_increment++); - GetLayerInfo(from).isBefore = true; - //_dependencies.Insert(0, (from, to)); - } - else - { - //GetLayerInfo(from).insertionIndex = _increment++; - GetLayerInfo(from).isBefore = false; - //_dependencies.Add((from, to)); - } - //_dependencies.Insert(0, (from, to)); - _dependencies.Add((from, to)); - } - private void AddDependency_Internal(LayerID from, string to, bool isBefore = false) - { - AddDependency_Internal(from, GetLayerID(to), isBefore); - } - private void AddDependency_Internal(string from, LayerID to, bool isBefore = false) - { - AddDependency_Internal(GetLayerID(from), to, isBefore); - } - private void AddDependency_Internal(string from, string to, bool isBefore = false) - { - AddDependency_Internal(GetLayerID(from), GetLayerID(to), isBefore); - } - #endregion - - #region Add - public DependencyHandler Add(string layer) - { - var id = GetLayerID(layer); - Add_Internal(id); - return new DependencyHandler(this, (int)id); - } - public DependencyHandler Add(params string[] layers) - { - return Add(layersRange: layers); - } - public DependencyHandler Add(IEnumerable layersRange) - { - foreach (var layer in layersRange) - { - Add_Internal(GetLayerID(layer)); - } - return new DependencyHandler(this, layersRange); - } - #endregion - - #region Move - public DependencyHandler Move(string layer) - { - return new DependencyHandler(this, (int)GetLayerID(layer)); - } - public DependencyHandler Move(params string[] layers) - { - return new DependencyHandler(this, layers); - } - public DependencyHandler Move(IEnumerable layersRange) - { - return new DependencyHandler(this, layersRange); - } - #endregion - - #region Remove - public void Remove(string layer) - { - Remove_Internal(GetLayerID(layer)); - } - public void Remove(params string[] layers) - { - Remove(layersRange: layers); - } - public void Remove(IEnumerable layersRange) - { - foreach (var layer in layersRange) - { - Remove_Internal(GetLayerID(layer)); - } - } - #endregion - - #region MergeWith - public void MergeWith(LayersMap other) - { - foreach (var otherDependency in other._dependencies) - { - AddDependency_Internal(other.GetLayerInfo(otherDependency.From).name, other.GetLayerInfo(otherDependency.To).name); - } - for (int i = 0; i < other._layerInfos.Count; i++) - { - LayerID otherLayerID = (LayerID)i; - ref var otherLayerInfo = ref other.GetLayerInfo(otherLayerID); - Add(otherLayerInfo.name); - } - } - #endregion - - private enum LayerID : int { NULL = 0 } - public readonly ref struct DependencyHandler - { - private readonly LayersMap _source; - private readonly LayerID _id; - private readonly IEnumerable _layersRange; - - #region Properties - public EcsPipeline.Builder Back - { - get { return _source._source; } - } - #endregion - - #region Constructors - public DependencyHandler(LayersMap source, int id) - { - _source = source; - _id = (LayerID)id; - _layersRange = null; - } - public DependencyHandler(LayersMap source, IEnumerable layersRange) - { - _source = source; - _id = LayerID.NULL; - _layersRange = layersRange; - } - #endregion - - #region Before - public DependencyHandler Before(params string[] targets) - { - return Before(range: targets); - } - public DependencyHandler Before(IEnumerable range) - { - foreach (var target in range) - { - Before(target); - } - return this; - } - public DependencyHandler Before(string targetLayer) - { - if (_id != LayerID.NULL) - { - _source.AddDependency_Internal(_id, targetLayer, true); - } - if (_layersRange != null) - { - foreach (var layer in _layersRange) - { - _source.AddDependency_Internal(layer, targetLayer, true); - } - } - return this; - } - #endregion - - #region After - public DependencyHandler After(params string[] targets) - { - return After(range: targets); - } - public DependencyHandler After(IEnumerable range) - { - foreach (var target in range) - { - After(target); - } - return this; - } - public DependencyHandler After(string target) - { - if (_id != LayerID.NULL) - { - _source.AddDependency_Internal(target, _id); - } - if (_layersRange != null) - { - foreach (var id in _layersRange) - { - _source.AddDependency_Internal(target, id); - } - } - return this; - } - #endregion - } - - #region Build - public string[] Build() - { - LayerID[] nodes = new LayerID[_count]; - var adjacency = new List<(LayerID To, int DependencyIndex)>[_layerInfos.Count]; - - for (int i = 0, j = 0; i < _layerInfos.Count; i++) - { - LayerID layerID = (LayerID)i; - ref var info = ref GetLayerInfo(layerID); - adjacency[(int)layerID] = new List<(LayerID To, int DependencyIndex)>(); - _layerInfos._items[(int)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 GetLayerInfo(from); - ref var toInfo = ref GetLayerInfo(to); - - if (fromInfo.isContained && toInfo.isContained) - { - adjacency[(int)from].Add((to, i)); - toInfo.inDegree += 1; - } - } - - //// добавление зависимостей для нод без зависимостей. - //if (_basicLayerID != LayerID.NULL) - //{ - // var basicLayerAdjacencyList = adjacency[(int)_basicLayerID]; - // int inserIndex = basicLayerAdjacencyList.Count; - // //for (int i = _layerInfos.Count - 1; i >= 0; i--) - // for (int i = 0; i < _layerInfos.Count; i++) - // { - // var id = (LayerID)i; - // ref var toInfo = ref _layerInfos._items[i]; - // if(toInfo.isContained && toInfo.hasAnyDependency == false) - // { - // //toInfo.insertionIndex = -toInfo.insertionIndex; - // basicLayerAdjacencyList.Insert(inserIndex, (id, toInfo.insertionIndex)); - // toInfo.inDegree += 1; - // } - // } - //} - - List zeroInDegree = new List(nodes.Length); - zeroInDegree.AddRange(nodes.Where(id => GetLayerInfo(id).inDegree == 0).OrderBy(id => GetLayerInfo(id).insertionIndex)); - - var result = new List(nodes.Length); - - while (zeroInDegree.Count > 0) - { - var current = zeroInDegree[0]; - zeroInDegree.RemoveAt(0); - - result.Add(GetLayerInfo(current).name); - - - var adjacencyList = adjacency[(int)current]; - //for (int i = adjacencyList.Count - 1; i >= 0; i--) - for (int i = 0; i < adjacencyList.Count; i++) - { - var (neighbor, _) = adjacencyList[i]; - ref var neighborInfo = ref GetLayerInfo(neighbor); - neighborInfo.inDegree--; - if (neighborInfo.inDegree == 0) - { - var neighborInsertionIndex = neighborInfo.insertionIndex; - int insertIndex = zeroInDegree.FindIndex(id => GetLayerInfo(id).insertionIndex < neighborInsertionIndex); - insertIndex = insertIndex < 0 ? 0 : insertIndex; - zeroInDegree.Insert(insertIndex, neighbor); - - //zeroInDegree.Add(neighbor); - //zeroInDegree = zeroInDegree.OrderBy(id => GetLayerInfo(id).insertionIndex).ToList(); - } - } - - //var adjacencyList = adjacency[(int)current]; - ////var adjacencyListSort = adjacencyList.OrderBy(o => GetLayerInfo(o.To).insertionIndex); - //var adjacencyListSort = adjacencyList; - //foreach (var item in adjacencyListSort) - //{ - // var (neighbor, _) = item; - // ref var neighborInfo = ref GetLayerInfo(neighbor); - // neighborInfo.inDegree--; - // if (neighborInfo.inDegree == 0) - // { - // //var neighborInsertionIndex = neighborInfo.insertionIndex; - // //int insertIndex = zeroInDegree.FindIndex(id => GetLayerInfo(id).insertionIndex > neighborInsertionIndex); - // //insertIndex = insertIndex < 0 ? 0 : insertIndex; - // // - // //zeroInDegree.Insert(insertIndex, neighbor); - // - // zeroInDegree.Add(neighbor); - // zeroInDegree = zeroInDegree.OrderBy(id => GetLayerInfo(id).insertionIndex).ToList(); - // } - //} - } - - if (result.Count != 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); - } - - return result.ToArray(); - } - #endregion - - #region FindCycles - private List FindCycle( - List<(LayerID To, int DependencyIndex)>[] adjacency, - LayerID[] 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( - LayerID node, - List<(LayerID 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<(LayerID To, int DependencyIndex)>[] adjacency) - { - var cycleEdges = new HashSet<(LayerID, LayerID)>(); - 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($"{GetLayerInfo(dep.From).name}->{GetLayerInfo(dep.To).name}"); - } - } - } - return dependencies.Distinct().ToArray(); - } - #endregion - - #region Other - public bool Contains(string layer) { return GetLayerInfo(GetLayerID(layer)).isContained; } - - public Enumerator GetEnumerator() { return new Enumerator(this); } - IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } - IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } - public struct Enumerator : IEnumerator - { - private LayersMap _map; - private int _index; - public Enumerator(LayersMap map) - { - _map = map; - _index = -1; - } - public string Current - { - get { return _map._layerInfos._items[_index].name; } - } - object IEnumerator.Current { get { return Current; } } - public bool MoveNext() - { - if (_index++ >= _map._layerInfos.Count) { return false; } - ref var info = ref _map._layerInfos._items[_index]; - if(info.isContained == false) - { - return MoveNext(); - } - else - { - return true; - } - } - public void Reset() { _index = -1; } - public void Dispose() { } - } - #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 _source; - } - [Obsolete("Use " + nameof(LayersMap) + ".Add(layer).After(targetLayer).Back;")] - public EcsPipeline.Builder InsertAfter(string targetLayer, string newLayer) - { - Add(newLayer).After(targetLayer); - return _source; - } - [Obsolete("Use " + nameof(LayersMap) + ".Move(layer).Before(targetLayer).Back;")] - public EcsPipeline.Builder Move(string targetLayer, string newLayer) - { - Move(newLayer).Before(targetLayer); - return _source; - } - [Obsolete("Use " + nameof(LayersMap) + ".Move(layer).After(targetLayer).Back;")] - public EcsPipeline.Builder MoveAfter(string targetLayer, string newLayer) - { - Move(newLayer).After(targetLayer); - return _source; - } - [Obsolete("Use " + nameof(LayersMap) + ".Add(layers).Before(targetLayer).Back;")] - public EcsPipeline.Builder Insert(string targetLayer, params string[] newLayers) - { - Add(newLayers).Before(targetLayer); - return _source; - } - [Obsolete("Use " + nameof(LayersMap) + ".Add(layers).After(targetLayer).Back;")] - public EcsPipeline.Builder InsertAfter(string targetLayer, params string[] newLayers) - { - Add(newLayers).After(targetLayer); - return _source; - } - [Obsolete("Use " + nameof(LayersMap) + ".Move(layers).Before(targetLayer).Back;")] - public EcsPipeline.Builder Move(string targetLayer, params string[] movingLayers) - { - Move(movingLayers).Before(targetLayer); - return _source; - } - [Obsolete("Use " + nameof(LayersMap) + ".Move(layers).After(targetLayer).Back;")] - public EcsPipeline.Builder MoveAfter(string targetLayer, params string[] movingLayers) - { - Move(movingLayers).After(targetLayer); - return _source; - } - - [Obsolete] - public object this[int index] - { - get - { - int i = 0; - foreach (var item in this) - { - if (i == index) - { - return item; - } - i++; - } - return null; - } - } - [Obsolete("Use MergeWith(LayersMap)")] - public void MergeWith(IReadOnlyList other) - { - foreach (var layer in other) - { - Add(layer); - } - } - #endregion - } -} \ No newline at end of file